using System;
using System.Collections.Generic;
using System.Diagnostics;
using Mbs.Messaging;
using Mbs.Collections;

namespace Mbs.Elements
{
    [DebuggerDisplay("Command={CommandName},Enabled={Enabled},Visible={Visible}")]
    class ElementCommand : MarshalAndDisposableObject, IElementCommand
    {
        public string CommandName { get; private set; }
        private IMap<IElement, IDisposable> elements = new ConcurrentMap<IElement, IDisposable>();

        private struct CommandDispose : IDisposable
        {
            private IDisposable Disposble;
            public CommandDispose(IDisposable dis, string @event)
            {
                Event = @event;
                Disposble = dis;
            }

            public void Dispose()
            {
                if (Disposble != null)
                    Disposble.Dispose();
            }
            public string Event;
        }

        public ElementCommand(string name)
        {
            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException("name");
            CommandName = name;
        }

        public IDisposable Attach(object owner, string @event)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
            if (string.IsNullOrEmpty(@event))
                throw new ArgumentNullException("event");

            var MB = ServiceLocator.Current.Get<IMessageBus>();
            IElement item = ServiceLocator.Current.Get<IElementService>().ElementMap.Register(owner);

            var result = MB.Attach(CommandName, owner, @event);
            elements.Add(item,new CommandDispose(result,@event));

            if (elements.Count >= 1)
            {
                item.Enabled = Enabled;
                item.Visible = Visible;
            }
            return result;
        }

        public string RemoveElement(IElement element)
        {
            if (element == null)
                return null;

            IDisposable dis = null;
            string @event = null;

            if (elements.TryGetValue(element, out dis))
            {
                @event = ((CommandDispose)dis).Event;
                dis.Dispose();
                elements.Remove(element);
            }

            return @event;
        }

        public List<TElement> Get<TElement>() where TElement : IElement
        {
            List<TElement> results = new List<TElement>();
            foreach (var item in elements.Keys)
                if (item is TElement)
                    results.Add((TElement)item);
            
            return results;
        }

        private bool? enabled = true;
        public bool? Enabled
        {
            get { return enabled; }
            set
            {
                if (value.HasValue && value.Value && (!visible.HasValue || (visible.HasValue && !visible.Value)))
                    Visible = true;

                if (enabled != value)
                {
                    enabled = value;
                    foreach (var item in elements)
                        item.Key.Enabled = value;
                }
            }
        }

        private bool? visible = true;
        public bool? Visible
        {
            get { return visible; }
            set
            {
                if (visible != value)
                {
                    visible = value;
                    foreach (var item in elements)
                        item.Key.Visible = value;
                }
            }
        }

        protected override void Dispose(bool disposing)
        {
            Visible = false;
            Enabled = false;

            foreach (var pair in elements)
                if (pair.Value != null)
                    pair.Value.Dispose();

            elements.Clear();
        }
       
        public override string ToString()
        {
            return CommandName;
        }
    }
}
